//
//  MessageContent.swift
//  tl2swift
//
//  Generated automatically. Any changes will be lost!
//  Based on TDLib 1.8.24-d79bd4b6
//  https://github.com/tdlib/td/tree/d79bd4b6
//

import Foundation


/// Contains the content of a message
public enum MessageContent: Codable, Equatable, Hashable {

    /// A text message
    case messageText(MessageText)

    /// An animation message (GIF-style).
    case messageAnimation(MessageAnimation)

    /// An audio message
    case messageAudio(MessageAudio)

    /// A document message (general file)
    case messageDocument(MessageDocument)

    /// A photo message
    case messagePhoto(MessagePhoto)

    /// A sticker message
    case messageSticker(MessageSticker)

    /// A video message
    case messageVideo(MessageVideo)

    /// A video note message
    case messageVideoNote(MessageVideoNote)

    /// A voice note message
    case messageVoiceNote(MessageVoiceNote)

    /// A self-destructed photo message
    case messageExpiredPhoto

    /// A self-destructed video message
    case messageExpiredVideo

    /// A self-destructed video note message
    case messageExpiredVideoNote

    /// A self-destructed voice note message
    case messageExpiredVoiceNote

    /// A message with a location
    case messageLocation(MessageLocation)

    /// A message with information about a venue
    case messageVenue(MessageVenue)

    /// A message with a user contact
    case messageContact(MessageContact)

    /// A message with an animated emoji
    case messageAnimatedEmoji(MessageAnimatedEmoji)

    /// A dice message. The dice value is randomly generated by the server
    case messageDice(MessageDice)

    /// A message with a game
    case messageGame(MessageGame)

    /// A message with a poll
    case messagePoll(MessagePoll)

    /// A message with a forwarded story
    case messageStory(MessageStory)

    /// A message with an invoice from a bot. Use getInternalLink with internalLinkTypeBotStart to share the invoice
    case messageInvoice(MessageInvoice)

    /// A message with information about an ended call
    case messageCall(MessageCall)

    /// A new video chat was scheduled
    case messageVideoChatScheduled(MessageVideoChatScheduled)

    /// A newly created video chat
    case messageVideoChatStarted(MessageVideoChatStarted)

    /// A message with information about an ended video chat
    case messageVideoChatEnded(MessageVideoChatEnded)

    /// A message with information about an invite to a video chat
    case messageInviteVideoChatParticipants(MessageInviteVideoChatParticipants)

    /// A newly created basic group
    case messageBasicGroupChatCreate(MessageBasicGroupChatCreate)

    /// A newly created supergroup or channel
    case messageSupergroupChatCreate(MessageSupergroupChatCreate)

    /// An updated chat title
    case messageChatChangeTitle(MessageChatChangeTitle)

    /// An updated chat photo
    case messageChatChangePhoto(MessageChatChangePhoto)

    /// A deleted chat photo
    case messageChatDeletePhoto

    /// New chat members were added
    case messageChatAddMembers(MessageChatAddMembers)

    /// A new member joined the chat via an invite link
    case messageChatJoinByLink

    /// A new member was accepted to the chat by an administrator
    case messageChatJoinByRequest

    /// A chat member was deleted
    case messageChatDeleteMember(MessageChatDeleteMember)

    /// A basic group was upgraded to a supergroup and was deactivated as the result
    case messageChatUpgradeTo(MessageChatUpgradeTo)

    /// A supergroup has been created from a basic group
    case messageChatUpgradeFrom(MessageChatUpgradeFrom)

    /// A message has been pinned
    case messagePinMessage(MessagePinMessage)

    /// A screenshot of a message in the chat has been taken
    case messageScreenshotTaken

    /// A new background was set in the chat
    case messageChatSetBackground(MessageChatSetBackground)

    /// A theme in the chat has been changed
    case messageChatSetTheme(MessageChatSetTheme)

    /// The auto-delete or self-destruct timer for messages in the chat has been changed
    case messageChatSetMessageAutoDeleteTime(MessageChatSetMessageAutoDeleteTime)

    /// A forum topic has been created
    case messageForumTopicCreated(MessageForumTopicCreated)

    /// A forum topic has been edited
    case messageForumTopicEdited(MessageForumTopicEdited)

    /// A forum topic has been closed or opened
    case messageForumTopicIsClosedToggled(MessageForumTopicIsClosedToggled)

    /// A General forum topic has been hidden or unhidden
    case messageForumTopicIsHiddenToggled(MessageForumTopicIsHiddenToggled)

    /// A profile photo was suggested to a user in a private chat
    case messageSuggestProfilePhoto(MessageSuggestProfilePhoto)

    /// A non-standard action has happened in the chat
    case messageCustomServiceAction(MessageCustomServiceAction)

    /// A new high score was achieved in a game
    case messageGameScore(MessageGameScore)

    /// A payment has been completed
    case messagePaymentSuccessful(MessagePaymentSuccessful)

    /// A payment has been completed; for bots only
    case messagePaymentSuccessfulBot(MessagePaymentSuccessfulBot)

    /// Telegram Premium was gifted to the user
    case messageGiftedPremium(MessageGiftedPremium)

    /// A Telegram Premium gift code was created for the user
    case messagePremiumGiftCode(MessagePremiumGiftCode)

    /// A Telegram Premium giveaway was created for the chat
    case messagePremiumGiveawayCreated

    /// A Telegram Premium giveaway
    case messagePremiumGiveaway(MessagePremiumGiveaway)

    /// A Telegram Premium giveaway without public winners has been completed for the chat
    case messagePremiumGiveawayCompleted(MessagePremiumGiveawayCompleted)

    /// A Telegram Premium giveaway with public winners has been completed for the chat
    case messagePremiumGiveawayWinners(MessagePremiumGiveawayWinners)

    /// A contact has registered with Telegram
    case messageContactRegistered

    /// The current user shared users, which were requested by the bot
    case messageUsersShared(MessageUsersShared)

    /// The current user shared a chat, which was requested by the bot
    case messageChatShared(MessageChatShared)

    /// The user allowed the bot to send messages
    case messageBotWriteAccessAllowed(MessageBotWriteAccessAllowed)

    /// Data from a Web App has been sent to a bot
    case messageWebAppDataSent(MessageWebAppDataSent)

    /// Data from a Web App has been received; for bots only
    case messageWebAppDataReceived(MessageWebAppDataReceived)

    /// Telegram Passport data has been sent to a bot
    case messagePassportDataSent(MessagePassportDataSent)

    /// Telegram Passport data has been received; for bots only
    case messagePassportDataReceived(MessagePassportDataReceived)

    /// A user in the chat came within proximity alert range
    case messageProximityAlertTriggered(MessageProximityAlertTriggered)

    /// A message content that is not supported in the current TDLib version
    case messageUnsupported


    private enum Kind: String, Codable {
        case messageText
        case messageAnimation
        case messageAudio
        case messageDocument
        case messagePhoto
        case messageSticker
        case messageVideo
        case messageVideoNote
        case messageVoiceNote
        case messageExpiredPhoto
        case messageExpiredVideo
        case messageExpiredVideoNote
        case messageExpiredVoiceNote
        case messageLocation
        case messageVenue
        case messageContact
        case messageAnimatedEmoji
        case messageDice
        case messageGame
        case messagePoll
        case messageStory
        case messageInvoice
        case messageCall
        case messageVideoChatScheduled
        case messageVideoChatStarted
        case messageVideoChatEnded
        case messageInviteVideoChatParticipants
        case messageBasicGroupChatCreate
        case messageSupergroupChatCreate
        case messageChatChangeTitle
        case messageChatChangePhoto
        case messageChatDeletePhoto
        case messageChatAddMembers
        case messageChatJoinByLink
        case messageChatJoinByRequest
        case messageChatDeleteMember
        case messageChatUpgradeTo
        case messageChatUpgradeFrom
        case messagePinMessage
        case messageScreenshotTaken
        case messageChatSetBackground
        case messageChatSetTheme
        case messageChatSetMessageAutoDeleteTime
        case messageForumTopicCreated
        case messageForumTopicEdited
        case messageForumTopicIsClosedToggled
        case messageForumTopicIsHiddenToggled
        case messageSuggestProfilePhoto
        case messageCustomServiceAction
        case messageGameScore
        case messagePaymentSuccessful
        case messagePaymentSuccessfulBot
        case messageGiftedPremium
        case messagePremiumGiftCode
        case messagePremiumGiveawayCreated
        case messagePremiumGiveaway
        case messagePremiumGiveawayCompleted
        case messagePremiumGiveawayWinners
        case messageContactRegistered
        case messageUsersShared
        case messageChatShared
        case messageBotWriteAccessAllowed
        case messageWebAppDataSent
        case messageWebAppDataReceived
        case messagePassportDataSent
        case messagePassportDataReceived
        case messageProximityAlertTriggered
        case messageUnsupported
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DtoCodingKeys.self)
        let type = try container.decode(Kind.self, forKey: .type)
        switch type {
        case .messageText:
            let value = try MessageText(from: decoder)
            self = .messageText(value)
        case .messageAnimation:
            let value = try MessageAnimation(from: decoder)
            self = .messageAnimation(value)
        case .messageAudio:
            let value = try MessageAudio(from: decoder)
            self = .messageAudio(value)
        case .messageDocument:
            let value = try MessageDocument(from: decoder)
            self = .messageDocument(value)
        case .messagePhoto:
            let value = try MessagePhoto(from: decoder)
            self = .messagePhoto(value)
        case .messageSticker:
            let value = try MessageSticker(from: decoder)
            self = .messageSticker(value)
        case .messageVideo:
            let value = try MessageVideo(from: decoder)
            self = .messageVideo(value)
        case .messageVideoNote:
            let value = try MessageVideoNote(from: decoder)
            self = .messageVideoNote(value)
        case .messageVoiceNote:
            let value = try MessageVoiceNote(from: decoder)
            self = .messageVoiceNote(value)
        case .messageExpiredPhoto:
            self = .messageExpiredPhoto
        case .messageExpiredVideo:
            self = .messageExpiredVideo
        case .messageExpiredVideoNote:
            self = .messageExpiredVideoNote
        case .messageExpiredVoiceNote:
            self = .messageExpiredVoiceNote
        case .messageLocation:
            let value = try MessageLocation(from: decoder)
            self = .messageLocation(value)
        case .messageVenue:
            let value = try MessageVenue(from: decoder)
            self = .messageVenue(value)
        case .messageContact:
            let value = try MessageContact(from: decoder)
            self = .messageContact(value)
        case .messageAnimatedEmoji:
            let value = try MessageAnimatedEmoji(from: decoder)
            self = .messageAnimatedEmoji(value)
        case .messageDice:
            let value = try MessageDice(from: decoder)
            self = .messageDice(value)
        case .messageGame:
            let value = try MessageGame(from: decoder)
            self = .messageGame(value)
        case .messagePoll:
            let value = try MessagePoll(from: decoder)
            self = .messagePoll(value)
        case .messageStory:
            let value = try MessageStory(from: decoder)
            self = .messageStory(value)
        case .messageInvoice:
            let value = try MessageInvoice(from: decoder)
            self = .messageInvoice(value)
        case .messageCall:
            let value = try MessageCall(from: decoder)
            self = .messageCall(value)
        case .messageVideoChatScheduled:
            let value = try MessageVideoChatScheduled(from: decoder)
            self = .messageVideoChatScheduled(value)
        case .messageVideoChatStarted:
            let value = try MessageVideoChatStarted(from: decoder)
            self = .messageVideoChatStarted(value)
        case .messageVideoChatEnded:
            let value = try MessageVideoChatEnded(from: decoder)
            self = .messageVideoChatEnded(value)
        case .messageInviteVideoChatParticipants:
            let value = try MessageInviteVideoChatParticipants(from: decoder)
            self = .messageInviteVideoChatParticipants(value)
        case .messageBasicGroupChatCreate:
            let value = try MessageBasicGroupChatCreate(from: decoder)
            self = .messageBasicGroupChatCreate(value)
        case .messageSupergroupChatCreate:
            let value = try MessageSupergroupChatCreate(from: decoder)
            self = .messageSupergroupChatCreate(value)
        case .messageChatChangeTitle:
            let value = try MessageChatChangeTitle(from: decoder)
            self = .messageChatChangeTitle(value)
        case .messageChatChangePhoto:
            let value = try MessageChatChangePhoto(from: decoder)
            self = .messageChatChangePhoto(value)
        case .messageChatDeletePhoto:
            self = .messageChatDeletePhoto
        case .messageChatAddMembers:
            let value = try MessageChatAddMembers(from: decoder)
            self = .messageChatAddMembers(value)
        case .messageChatJoinByLink:
            self = .messageChatJoinByLink
        case .messageChatJoinByRequest:
            self = .messageChatJoinByRequest
        case .messageChatDeleteMember:
            let value = try MessageChatDeleteMember(from: decoder)
            self = .messageChatDeleteMember(value)
        case .messageChatUpgradeTo:
            let value = try MessageChatUpgradeTo(from: decoder)
            self = .messageChatUpgradeTo(value)
        case .messageChatUpgradeFrom:
            let value = try MessageChatUpgradeFrom(from: decoder)
            self = .messageChatUpgradeFrom(value)
        case .messagePinMessage:
            let value = try MessagePinMessage(from: decoder)
            self = .messagePinMessage(value)
        case .messageScreenshotTaken:
            self = .messageScreenshotTaken
        case .messageChatSetBackground:
            let value = try MessageChatSetBackground(from: decoder)
            self = .messageChatSetBackground(value)
        case .messageChatSetTheme:
            let value = try MessageChatSetTheme(from: decoder)
            self = .messageChatSetTheme(value)
        case .messageChatSetMessageAutoDeleteTime:
            let value = try MessageChatSetMessageAutoDeleteTime(from: decoder)
            self = .messageChatSetMessageAutoDeleteTime(value)
        case .messageForumTopicCreated:
            let value = try MessageForumTopicCreated(from: decoder)
            self = .messageForumTopicCreated(value)
        case .messageForumTopicEdited:
            let value = try MessageForumTopicEdited(from: decoder)
            self = .messageForumTopicEdited(value)
        case .messageForumTopicIsClosedToggled:
            let value = try MessageForumTopicIsClosedToggled(from: decoder)
            self = .messageForumTopicIsClosedToggled(value)
        case .messageForumTopicIsHiddenToggled:
            let value = try MessageForumTopicIsHiddenToggled(from: decoder)
            self = .messageForumTopicIsHiddenToggled(value)
        case .messageSuggestProfilePhoto:
            let value = try MessageSuggestProfilePhoto(from: decoder)
            self = .messageSuggestProfilePhoto(value)
        case .messageCustomServiceAction:
            let value = try MessageCustomServiceAction(from: decoder)
            self = .messageCustomServiceAction(value)
        case .messageGameScore:
            let value = try MessageGameScore(from: decoder)
            self = .messageGameScore(value)
        case .messagePaymentSuccessful:
            let value = try MessagePaymentSuccessful(from: decoder)
            self = .messagePaymentSuccessful(value)
        case .messagePaymentSuccessfulBot:
            let value = try MessagePaymentSuccessfulBot(from: decoder)
            self = .messagePaymentSuccessfulBot(value)
        case .messageGiftedPremium:
            let value = try MessageGiftedPremium(from: decoder)
            self = .messageGiftedPremium(value)
        case .messagePremiumGiftCode:
            let value = try MessagePremiumGiftCode(from: decoder)
            self = .messagePremiumGiftCode(value)
        case .messagePremiumGiveawayCreated:
            self = .messagePremiumGiveawayCreated
        case .messagePremiumGiveaway:
            let value = try MessagePremiumGiveaway(from: decoder)
            self = .messagePremiumGiveaway(value)
        case .messagePremiumGiveawayCompleted:
            let value = try MessagePremiumGiveawayCompleted(from: decoder)
            self = .messagePremiumGiveawayCompleted(value)
        case .messagePremiumGiveawayWinners:
            let value = try MessagePremiumGiveawayWinners(from: decoder)
            self = .messagePremiumGiveawayWinners(value)
        case .messageContactRegistered:
            self = .messageContactRegistered
        case .messageUsersShared:
            let value = try MessageUsersShared(from: decoder)
            self = .messageUsersShared(value)
        case .messageChatShared:
            let value = try MessageChatShared(from: decoder)
            self = .messageChatShared(value)
        case .messageBotWriteAccessAllowed:
            let value = try MessageBotWriteAccessAllowed(from: decoder)
            self = .messageBotWriteAccessAllowed(value)
        case .messageWebAppDataSent:
            let value = try MessageWebAppDataSent(from: decoder)
            self = .messageWebAppDataSent(value)
        case .messageWebAppDataReceived:
            let value = try MessageWebAppDataReceived(from: decoder)
            self = .messageWebAppDataReceived(value)
        case .messagePassportDataSent:
            let value = try MessagePassportDataSent(from: decoder)
            self = .messagePassportDataSent(value)
        case .messagePassportDataReceived:
            let value = try MessagePassportDataReceived(from: decoder)
            self = .messagePassportDataReceived(value)
        case .messageProximityAlertTriggered:
            let value = try MessageProximityAlertTriggered(from: decoder)
            self = .messageProximityAlertTriggered(value)
        case .messageUnsupported:
            self = .messageUnsupported
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: DtoCodingKeys.self)
        switch self {
        case .messageText(let value):
            try container.encode(Kind.messageText, forKey: .type)
            try value.encode(to: encoder)
        case .messageAnimation(let value):
            try container.encode(Kind.messageAnimation, forKey: .type)
            try value.encode(to: encoder)
        case .messageAudio(let value):
            try container.encode(Kind.messageAudio, forKey: .type)
            try value.encode(to: encoder)
        case .messageDocument(let value):
            try container.encode(Kind.messageDocument, forKey: .type)
            try value.encode(to: encoder)
        case .messagePhoto(let value):
            try container.encode(Kind.messagePhoto, forKey: .type)
            try value.encode(to: encoder)
        case .messageSticker(let value):
            try container.encode(Kind.messageSticker, forKey: .type)
            try value.encode(to: encoder)
        case .messageVideo(let value):
            try container.encode(Kind.messageVideo, forKey: .type)
            try value.encode(to: encoder)
        case .messageVideoNote(let value):
            try container.encode(Kind.messageVideoNote, forKey: .type)
            try value.encode(to: encoder)
        case .messageVoiceNote(let value):
            try container.encode(Kind.messageVoiceNote, forKey: .type)
            try value.encode(to: encoder)
        case .messageExpiredPhoto:
            try container.encode(Kind.messageExpiredPhoto, forKey: .type)
        case .messageExpiredVideo:
            try container.encode(Kind.messageExpiredVideo, forKey: .type)
        case .messageExpiredVideoNote:
            try container.encode(Kind.messageExpiredVideoNote, forKey: .type)
        case .messageExpiredVoiceNote:
            try container.encode(Kind.messageExpiredVoiceNote, forKey: .type)
        case .messageLocation(let value):
            try container.encode(Kind.messageLocation, forKey: .type)
            try value.encode(to: encoder)
        case .messageVenue(let value):
            try container.encode(Kind.messageVenue, forKey: .type)
            try value.encode(to: encoder)
        case .messageContact(let value):
            try container.encode(Kind.messageContact, forKey: .type)
            try value.encode(to: encoder)
        case .messageAnimatedEmoji(let value):
            try container.encode(Kind.messageAnimatedEmoji, forKey: .type)
            try value.encode(to: encoder)
        case .messageDice(let value):
            try container.encode(Kind.messageDice, forKey: .type)
            try value.encode(to: encoder)
        case .messageGame(let value):
            try container.encode(Kind.messageGame, forKey: .type)
            try value.encode(to: encoder)
        case .messagePoll(let value):
            try container.encode(Kind.messagePoll, forKey: .type)
            try value.encode(to: encoder)
        case .messageStory(let value):
            try container.encode(Kind.messageStory, forKey: .type)
            try value.encode(to: encoder)
        case .messageInvoice(let value):
            try container.encode(Kind.messageInvoice, forKey: .type)
            try value.encode(to: encoder)
        case .messageCall(let value):
            try container.encode(Kind.messageCall, forKey: .type)
            try value.encode(to: encoder)
        case .messageVideoChatScheduled(let value):
            try container.encode(Kind.messageVideoChatScheduled, forKey: .type)
            try value.encode(to: encoder)
        case .messageVideoChatStarted(let value):
            try container.encode(Kind.messageVideoChatStarted, forKey: .type)
            try value.encode(to: encoder)
        case .messageVideoChatEnded(let value):
            try container.encode(Kind.messageVideoChatEnded, forKey: .type)
            try value.encode(to: encoder)
        case .messageInviteVideoChatParticipants(let value):
            try container.encode(Kind.messageInviteVideoChatParticipants, forKey: .type)
            try value.encode(to: encoder)
        case .messageBasicGroupChatCreate(let value):
            try container.encode(Kind.messageBasicGroupChatCreate, forKey: .type)
            try value.encode(to: encoder)
        case .messageSupergroupChatCreate(let value):
            try container.encode(Kind.messageSupergroupChatCreate, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatChangeTitle(let value):
            try container.encode(Kind.messageChatChangeTitle, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatChangePhoto(let value):
            try container.encode(Kind.messageChatChangePhoto, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatDeletePhoto:
            try container.encode(Kind.messageChatDeletePhoto, forKey: .type)
        case .messageChatAddMembers(let value):
            try container.encode(Kind.messageChatAddMembers, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatJoinByLink:
            try container.encode(Kind.messageChatJoinByLink, forKey: .type)
        case .messageChatJoinByRequest:
            try container.encode(Kind.messageChatJoinByRequest, forKey: .type)
        case .messageChatDeleteMember(let value):
            try container.encode(Kind.messageChatDeleteMember, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatUpgradeTo(let value):
            try container.encode(Kind.messageChatUpgradeTo, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatUpgradeFrom(let value):
            try container.encode(Kind.messageChatUpgradeFrom, forKey: .type)
            try value.encode(to: encoder)
        case .messagePinMessage(let value):
            try container.encode(Kind.messagePinMessage, forKey: .type)
            try value.encode(to: encoder)
        case .messageScreenshotTaken:
            try container.encode(Kind.messageScreenshotTaken, forKey: .type)
        case .messageChatSetBackground(let value):
            try container.encode(Kind.messageChatSetBackground, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatSetTheme(let value):
            try container.encode(Kind.messageChatSetTheme, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatSetMessageAutoDeleteTime(let value):
            try container.encode(Kind.messageChatSetMessageAutoDeleteTime, forKey: .type)
            try value.encode(to: encoder)
        case .messageForumTopicCreated(let value):
            try container.encode(Kind.messageForumTopicCreated, forKey: .type)
            try value.encode(to: encoder)
        case .messageForumTopicEdited(let value):
            try container.encode(Kind.messageForumTopicEdited, forKey: .type)
            try value.encode(to: encoder)
        case .messageForumTopicIsClosedToggled(let value):
            try container.encode(Kind.messageForumTopicIsClosedToggled, forKey: .type)
            try value.encode(to: encoder)
        case .messageForumTopicIsHiddenToggled(let value):
            try container.encode(Kind.messageForumTopicIsHiddenToggled, forKey: .type)
            try value.encode(to: encoder)
        case .messageSuggestProfilePhoto(let value):
            try container.encode(Kind.messageSuggestProfilePhoto, forKey: .type)
            try value.encode(to: encoder)
        case .messageCustomServiceAction(let value):
            try container.encode(Kind.messageCustomServiceAction, forKey: .type)
            try value.encode(to: encoder)
        case .messageGameScore(let value):
            try container.encode(Kind.messageGameScore, forKey: .type)
            try value.encode(to: encoder)
        case .messagePaymentSuccessful(let value):
            try container.encode(Kind.messagePaymentSuccessful, forKey: .type)
            try value.encode(to: encoder)
        case .messagePaymentSuccessfulBot(let value):
            try container.encode(Kind.messagePaymentSuccessfulBot, forKey: .type)
            try value.encode(to: encoder)
        case .messageGiftedPremium(let value):
            try container.encode(Kind.messageGiftedPremium, forKey: .type)
            try value.encode(to: encoder)
        case .messagePremiumGiftCode(let value):
            try container.encode(Kind.messagePremiumGiftCode, forKey: .type)
            try value.encode(to: encoder)
        case .messagePremiumGiveawayCreated:
            try container.encode(Kind.messagePremiumGiveawayCreated, forKey: .type)
        case .messagePremiumGiveaway(let value):
            try container.encode(Kind.messagePremiumGiveaway, forKey: .type)
            try value.encode(to: encoder)
        case .messagePremiumGiveawayCompleted(let value):
            try container.encode(Kind.messagePremiumGiveawayCompleted, forKey: .type)
            try value.encode(to: encoder)
        case .messagePremiumGiveawayWinners(let value):
            try container.encode(Kind.messagePremiumGiveawayWinners, forKey: .type)
            try value.encode(to: encoder)
        case .messageContactRegistered:
            try container.encode(Kind.messageContactRegistered, forKey: .type)
        case .messageUsersShared(let value):
            try container.encode(Kind.messageUsersShared, forKey: .type)
            try value.encode(to: encoder)
        case .messageChatShared(let value):
            try container.encode(Kind.messageChatShared, forKey: .type)
            try value.encode(to: encoder)
        case .messageBotWriteAccessAllowed(let value):
            try container.encode(Kind.messageBotWriteAccessAllowed, forKey: .type)
            try value.encode(to: encoder)
        case .messageWebAppDataSent(let value):
            try container.encode(Kind.messageWebAppDataSent, forKey: .type)
            try value.encode(to: encoder)
        case .messageWebAppDataReceived(let value):
            try container.encode(Kind.messageWebAppDataReceived, forKey: .type)
            try value.encode(to: encoder)
        case .messagePassportDataSent(let value):
            try container.encode(Kind.messagePassportDataSent, forKey: .type)
            try value.encode(to: encoder)
        case .messagePassportDataReceived(let value):
            try container.encode(Kind.messagePassportDataReceived, forKey: .type)
            try value.encode(to: encoder)
        case .messageProximityAlertTriggered(let value):
            try container.encode(Kind.messageProximityAlertTriggered, forKey: .type)
            try value.encode(to: encoder)
        case .messageUnsupported:
            try container.encode(Kind.messageUnsupported, forKey: .type)
        }
    }
}

/// A text message
public struct MessageText: Codable, Equatable, Hashable {

    /// Options which were used for generation of the link preview; may be null if default options were used
    public let linkPreviewOptions: LinkPreviewOptions?

    /// Text of the message
    public let text: FormattedText

    /// A link preview attached to the message; may be null
    public let webPage: WebPage?


    public init(
        linkPreviewOptions: LinkPreviewOptions?,
        text: FormattedText,
        webPage: WebPage?
    ) {
        self.linkPreviewOptions = linkPreviewOptions
        self.text = text
        self.webPage = webPage
    }
}

/// An animation message (GIF-style).
public struct MessageAnimation: Codable, Equatable, Hashable {

    /// The animation description
    public let animation: Animation

    /// Animation caption
    public let caption: FormattedText

    /// True, if the animation preview must be covered by a spoiler animation
    public let hasSpoiler: Bool

    /// True, if the animation thumbnail must be blurred and the animation must be shown only while tapped
    public let isSecret: Bool


    public init(
        animation: Animation,
        caption: FormattedText,
        hasSpoiler: Bool,
        isSecret: Bool
    ) {
        self.animation = animation
        self.caption = caption
        self.hasSpoiler = hasSpoiler
        self.isSecret = isSecret
    }
}

/// An audio message
public struct MessageAudio: Codable, Equatable, Hashable {

    /// The audio description
    public let audio: Audio

    /// Audio caption
    public let caption: FormattedText


    public init(
        audio: Audio,
        caption: FormattedText
    ) {
        self.audio = audio
        self.caption = caption
    }
}

/// A document message (general file)
public struct MessageDocument: Codable, Equatable, Hashable {

    /// Document caption
    public let caption: FormattedText

    /// The document description
    public let document: Document


    public init(
        caption: FormattedText,
        document: Document
    ) {
        self.caption = caption
        self.document = document
    }
}

/// A photo message
public struct MessagePhoto: Codable, Equatable, Hashable {

    /// Photo caption
    public let caption: FormattedText

    /// True, if the photo preview must be covered by a spoiler animation
    public let hasSpoiler: Bool

    /// True, if the photo must be blurred and must be shown only while tapped
    public let isSecret: Bool

    /// The photo
    public let photo: Photo


    public init(
        caption: FormattedText,
        hasSpoiler: Bool,
        isSecret: Bool,
        photo: Photo
    ) {
        self.caption = caption
        self.hasSpoiler = hasSpoiler
        self.isSecret = isSecret
        self.photo = photo
    }
}

/// A sticker message
public struct MessageSticker: Codable, Equatable, Hashable {

    /// True, if premium animation of the sticker must be played
    public let isPremium: Bool

    /// The sticker description
    public let sticker: Sticker


    public init(
        isPremium: Bool,
        sticker: Sticker
    ) {
        self.isPremium = isPremium
        self.sticker = sticker
    }
}

/// A video message
public struct MessageVideo: Codable, Equatable, Hashable {

    /// Video caption
    public let caption: FormattedText

    /// True, if the video preview must be covered by a spoiler animation
    public let hasSpoiler: Bool

    /// True, if the video thumbnail must be blurred and the video must be shown only while tapped
    public let isSecret: Bool

    /// The video description
    public let video: Video


    public init(
        caption: FormattedText,
        hasSpoiler: Bool,
        isSecret: Bool,
        video: Video
    ) {
        self.caption = caption
        self.hasSpoiler = hasSpoiler
        self.isSecret = isSecret
        self.video = video
    }
}

/// A video note message
public struct MessageVideoNote: Codable, Equatable, Hashable {

    /// True, if the video note thumbnail must be blurred and the video note must be shown only while tapped
    public let isSecret: Bool

    /// True, if at least one of the recipients has viewed the video note
    public let isViewed: Bool

    /// The video note description
    public let videoNote: VideoNote


    public init(
        isSecret: Bool,
        isViewed: Bool,
        videoNote: VideoNote
    ) {
        self.isSecret = isSecret
        self.isViewed = isViewed
        self.videoNote = videoNote
    }
}

/// A voice note message
public struct MessageVoiceNote: Codable, Equatable, Hashable {

    /// Voice note caption
    public let caption: FormattedText

    /// True, if at least one of the recipients has listened to the voice note
    public let isListened: Bool

    /// The voice note description
    public let voiceNote: VoiceNote


    public init(
        caption: FormattedText,
        isListened: Bool,
        voiceNote: VoiceNote
    ) {
        self.caption = caption
        self.isListened = isListened
        self.voiceNote = voiceNote
    }
}

/// A message with a location
public struct MessageLocation: Codable, Equatable, Hashable {

    /// Left time for which the location can be updated, in seconds. updateMessageContent is not sent when this field changes
    public let expiresIn: Int

    /// For live locations, a direction in which the location moves, in degrees; 1-360. If 0 the direction is unknown
    public let heading: Int

    /// Time relative to the message send date, for which the location can be updated, in seconds
    public let livePeriod: Int

    /// The location description
    public let location: Location

    /// For live locations, a maximum distance to another chat member for proximity alerts, in meters (0-100000). 0 if the notification is disabled. Available only to the message sender
    public let proximityAlertRadius: Int


    public init(
        expiresIn: Int,
        heading: Int,
        livePeriod: Int,
        location: Location,
        proximityAlertRadius: Int
    ) {
        self.expiresIn = expiresIn
        self.heading = heading
        self.livePeriod = livePeriod
        self.location = location
        self.proximityAlertRadius = proximityAlertRadius
    }
}

/// A message with information about a venue
public struct MessageVenue: Codable, Equatable, Hashable {

    /// The venue description
    public let venue: Venue


    public init(venue: Venue) {
        self.venue = venue
    }
}

/// A message with a user contact
public struct MessageContact: Codable, Equatable, Hashable {

    /// The contact description
    public let contact: Contact


    public init(contact: Contact) {
        self.contact = contact
    }
}

/// A message with an animated emoji
public struct MessageAnimatedEmoji: Codable, Equatable, Hashable {

    /// The animated emoji
    public let animatedEmoji: AnimatedEmoji

    /// The corresponding emoji
    public let emoji: String


    public init(
        animatedEmoji: AnimatedEmoji,
        emoji: String
    ) {
        self.animatedEmoji = animatedEmoji
        self.emoji = emoji
    }
}

/// A dice message. The dice value is randomly generated by the server
public struct MessageDice: Codable, Equatable, Hashable {

    /// Emoji on which the dice throw animation is based
    public let emoji: String

    /// The animated stickers with the final dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known
    public let finalState: DiceStickers?

    /// The animated stickers with the initial dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known
    public let initialState: DiceStickers?

    /// Number of frame after which a success animation like a shower of confetti needs to be shown on updateMessageSendSucceeded
    public let successAnimationFrameNumber: Int

    /// The dice value. If the value is 0, the dice don't have final state yet
    public let value: Int


    public init(
        emoji: String,
        finalState: DiceStickers?,
        initialState: DiceStickers?,
        successAnimationFrameNumber: Int,
        value: Int
    ) {
        self.emoji = emoji
        self.finalState = finalState
        self.initialState = initialState
        self.successAnimationFrameNumber = successAnimationFrameNumber
        self.value = value
    }
}

/// A message with a game
public struct MessageGame: Codable, Equatable, Hashable {

    /// The game description
    public let game: Game


    public init(game: Game) {
        self.game = game
    }
}

/// A message with a poll
public struct MessagePoll: Codable, Equatable, Hashable {

    /// The poll description
    public let poll: Poll


    public init(poll: Poll) {
        self.poll = poll
    }
}

/// A message with a forwarded story
public struct MessageStory: Codable, Equatable, Hashable {

    /// Story identifier
    public let storyId: Int

    /// Identifier of the chat that posted the story
    public let storySenderChatId: Int64

    /// True, if the story was automatically forwarded because of a mention of the user
    public let viaMention: Bool


    public init(
        storyId: Int,
        storySenderChatId: Int64,
        viaMention: Bool
    ) {
        self.storyId = storyId
        self.storySenderChatId = storySenderChatId
        self.viaMention = viaMention
    }
}

/// A message with an invoice from a bot. Use getInternalLink with internalLinkTypeBotStart to share the invoice
public struct MessageInvoice: Codable, Equatable, Hashable {

    /// Currency for the product price
    public let currency: String

    public let description: FormattedText

    /// Extended media attached to the invoice; may be null
    public let extendedMedia: MessageExtendedMedia?

    /// True, if the invoice is a test invoice
    public let isTest: Bool

    /// True, if the shipping address must be specified
    public let needShippingAddress: Bool

    /// Product photo; may be null
    public let photo: Photo?

    /// The identifier of the message with the receipt, after the product has been purchased
    public let receiptMessageId: Int64

    /// Unique invoice bot start_parameter to be passed to getInternalLink
    public let startParameter: String

    /// Product title
    public let title: String

    /// Product total price in the smallest units of the currency
    public let totalAmount: Int64


    public init(
        currency: String,
        description: FormattedText,
        extendedMedia: MessageExtendedMedia?,
        isTest: Bool,
        needShippingAddress: Bool,
        photo: Photo?,
        receiptMessageId: Int64,
        startParameter: String,
        title: String,
        totalAmount: Int64
    ) {
        self.currency = currency
        self.description = description
        self.extendedMedia = extendedMedia
        self.isTest = isTest
        self.needShippingAddress = needShippingAddress
        self.photo = photo
        self.receiptMessageId = receiptMessageId
        self.startParameter = startParameter
        self.title = title
        self.totalAmount = totalAmount
    }
}

/// A message with information about an ended call
public struct MessageCall: Codable, Equatable, Hashable {

    /// Reason why the call was discarded
    public let discardReason: CallDiscardReason

    /// Call duration, in seconds
    public let duration: Int

    /// True, if the call was a video call
    public let isVideo: Bool


    public init(
        discardReason: CallDiscardReason,
        duration: Int,
        isVideo: Bool
    ) {
        self.discardReason = discardReason
        self.duration = duration
        self.isVideo = isVideo
    }
}

/// A new video chat was scheduled
public struct MessageVideoChatScheduled: Codable, Equatable, Hashable {

    /// Identifier of the video chat. The video chat can be received through the method getGroupCall
    public let groupCallId: Int

    /// Point in time (Unix timestamp) when the group call is supposed to be started by an administrator
    public let startDate: Int


    public init(
        groupCallId: Int,
        startDate: Int
    ) {
        self.groupCallId = groupCallId
        self.startDate = startDate
    }
}

/// A newly created video chat
public struct MessageVideoChatStarted: Codable, Equatable, Hashable {

    /// Identifier of the video chat. The video chat can be received through the method getGroupCall
    public let groupCallId: Int


    public init(groupCallId: Int) {
        self.groupCallId = groupCallId
    }
}

/// A message with information about an ended video chat
public struct MessageVideoChatEnded: Codable, Equatable, Hashable {

    /// Call duration, in seconds
    public let duration: Int


    public init(duration: Int) {
        self.duration = duration
    }
}

/// A message with information about an invite to a video chat
public struct MessageInviteVideoChatParticipants: Codable, Equatable, Hashable {

    /// Identifier of the video chat. The video chat can be received through the method getGroupCall
    public let groupCallId: Int

    /// Invited user identifiers
    public let userIds: [Int64]


    public init(
        groupCallId: Int,
        userIds: [Int64]
    ) {
        self.groupCallId = groupCallId
        self.userIds = userIds
    }
}

/// A newly created basic group
public struct MessageBasicGroupChatCreate: Codable, Equatable, Hashable {

    /// User identifiers of members in the basic group
    public let memberUserIds: [Int64]

    /// Title of the basic group
    public let title: String


    public init(
        memberUserIds: [Int64],
        title: String
    ) {
        self.memberUserIds = memberUserIds
        self.title = title
    }
}

/// A newly created supergroup or channel
public struct MessageSupergroupChatCreate: Codable, Equatable, Hashable {

    /// Title of the supergroup or channel
    public let title: String


    public init(title: String) {
        self.title = title
    }
}

/// An updated chat title
public struct MessageChatChangeTitle: Codable, Equatable, Hashable {

    /// New chat title
    public let title: String


    public init(title: String) {
        self.title = title
    }
}

/// An updated chat photo
public struct MessageChatChangePhoto: Codable, Equatable, Hashable {

    /// New chat photo
    public let photo: ChatPhoto


    public init(photo: ChatPhoto) {
        self.photo = photo
    }
}

/// New chat members were added
public struct MessageChatAddMembers: Codable, Equatable, Hashable {

    /// User identifiers of the new members
    public let memberUserIds: [Int64]


    public init(memberUserIds: [Int64]) {
        self.memberUserIds = memberUserIds
    }
}

/// A chat member was deleted
public struct MessageChatDeleteMember: Codable, Equatable, Hashable {

    /// User identifier of the deleted chat member
    public let userId: Int64


    public init(userId: Int64) {
        self.userId = userId
    }
}

/// A basic group was upgraded to a supergroup and was deactivated as the result
public struct MessageChatUpgradeTo: Codable, Equatable, Hashable {

    /// Identifier of the supergroup to which the basic group was upgraded
    public let supergroupId: Int64


    public init(supergroupId: Int64) {
        self.supergroupId = supergroupId
    }
}

/// A supergroup has been created from a basic group
public struct MessageChatUpgradeFrom: Codable, Equatable, Hashable {

    /// The identifier of the original basic group
    public let basicGroupId: Int64

    /// Title of the newly created supergroup
    public let title: String


    public init(
        basicGroupId: Int64,
        title: String
    ) {
        self.basicGroupId = basicGroupId
        self.title = title
    }
}

/// A message has been pinned
public struct MessagePinMessage: Codable, Equatable, Hashable {

    /// Identifier of the pinned message, can be an identifier of a deleted message or 0
    public let messageId: Int64


    public init(messageId: Int64) {
        self.messageId = messageId
    }
}

/// A new background was set in the chat
public struct MessageChatSetBackground: Codable, Equatable, Hashable {

    /// The new background
    public let background: ChatBackground

    /// Identifier of the message with a previously set same background; 0 if none. Can be an identifier of a deleted message
    public let oldBackgroundMessageId: Int64

    /// True, if the background was set only for self
    public let onlyForSelf: Bool


    public init(
        background: ChatBackground,
        oldBackgroundMessageId: Int64,
        onlyForSelf: Bool
    ) {
        self.background = background
        self.oldBackgroundMessageId = oldBackgroundMessageId
        self.onlyForSelf = onlyForSelf
    }
}

/// A theme in the chat has been changed
public struct MessageChatSetTheme: Codable, Equatable, Hashable {

    /// If non-empty, name of a new theme, set for the chat. Otherwise, chat theme was reset to the default one
    public let themeName: String


    public init(themeName: String) {
        self.themeName = themeName
    }
}

/// The auto-delete or self-destruct timer for messages in the chat has been changed
public struct MessageChatSetMessageAutoDeleteTime: Codable, Equatable, Hashable {

    /// If not 0, a user identifier, which default setting was automatically applied
    public let fromUserId: Int64

    /// New value auto-delete or self-destruct time, in seconds; 0 if disabled
    public let messageAutoDeleteTime: Int


    public init(
        fromUserId: Int64,
        messageAutoDeleteTime: Int
    ) {
        self.fromUserId = fromUserId
        self.messageAutoDeleteTime = messageAutoDeleteTime
    }
}

/// A forum topic has been created
public struct MessageForumTopicCreated: Codable, Equatable, Hashable {

    /// Icon of the topic
    public let icon: ForumTopicIcon

    /// Name of the topic
    public let name: String


    public init(
        icon: ForumTopicIcon,
        name: String
    ) {
        self.icon = icon
        self.name = name
    }
}

/// A forum topic has been edited
public struct MessageForumTopicEdited: Codable, Equatable, Hashable {

    /// True, if icon's custom_emoji_id is changed
    public let editIconCustomEmojiId: Bool

    /// New unique identifier of the custom emoji shown on the topic icon; 0 if none. Must be ignored if edit_icon_custom_emoji_id is false
    public let iconCustomEmojiId: TdInt64

    /// If non-empty, the new name of the topic
    public let name: String


    public init(
        editIconCustomEmojiId: Bool,
        iconCustomEmojiId: TdInt64,
        name: String
    ) {
        self.editIconCustomEmojiId = editIconCustomEmojiId
        self.iconCustomEmojiId = iconCustomEmojiId
        self.name = name
    }
}

/// A forum topic has been closed or opened
public struct MessageForumTopicIsClosedToggled: Codable, Equatable, Hashable {

    /// True, if the topic was closed; otherwise, the topic was reopened
    public let isClosed: Bool


    public init(isClosed: Bool) {
        self.isClosed = isClosed
    }
}

/// A General forum topic has been hidden or unhidden
public struct MessageForumTopicIsHiddenToggled: Codable, Equatable, Hashable {

    /// True, if the topic was hidden; otherwise, the topic was unhidden
    public let isHidden: Bool


    public init(isHidden: Bool) {
        self.isHidden = isHidden
    }
}

/// A profile photo was suggested to a user in a private chat
public struct MessageSuggestProfilePhoto: Codable, Equatable, Hashable {

    /// The suggested chat photo. Use the method setProfilePhoto with inputChatPhotoPrevious to apply the photo
    public let photo: ChatPhoto


    public init(photo: ChatPhoto) {
        self.photo = photo
    }
}

/// A non-standard action has happened in the chat
public struct MessageCustomServiceAction: Codable, Equatable, Hashable {

    /// Message text to be shown in the chat
    public let text: String


    public init(text: String) {
        self.text = text
    }
}

/// A new high score was achieved in a game
public struct MessageGameScore: Codable, Equatable, Hashable {

    /// Identifier of the game; may be different from the games presented in the message with the game
    public let gameId: TdInt64

    /// Identifier of the message with the game, can be an identifier of a deleted message
    public let gameMessageId: Int64

    /// New score
    public let score: Int


    public init(
        gameId: TdInt64,
        gameMessageId: Int64,
        score: Int
    ) {
        self.gameId = gameId
        self.gameMessageId = gameMessageId
        self.score = score
    }
}

/// A payment has been completed
public struct MessagePaymentSuccessful: Codable, Equatable, Hashable {

    /// Currency for the price of the product
    public let currency: String

    /// Identifier of the chat, containing the corresponding invoice message
    public let invoiceChatId: Int64

    /// Identifier of the message with the corresponding invoice; can be 0 or an identifier of a deleted message
    public let invoiceMessageId: Int64

    /// Name of the invoice; may be empty if unknown
    public let invoiceName: String

    /// True, if this is the first recurring payment
    public let isFirstRecurring: Bool

    /// True, if this is a recurring payment
    public let isRecurring: Bool

    /// Total price for the product, in the smallest units of the currency
    public let totalAmount: Int64


    public init(
        currency: String,
        invoiceChatId: Int64,
        invoiceMessageId: Int64,
        invoiceName: String,
        isFirstRecurring: Bool,
        isRecurring: Bool,
        totalAmount: Int64
    ) {
        self.currency = currency
        self.invoiceChatId = invoiceChatId
        self.invoiceMessageId = invoiceMessageId
        self.invoiceName = invoiceName
        self.isFirstRecurring = isFirstRecurring
        self.isRecurring = isRecurring
        self.totalAmount = totalAmount
    }
}

/// A payment has been completed; for bots only
public struct MessagePaymentSuccessfulBot: Codable, Equatable, Hashable {

    /// Currency for price of the product
    public let currency: String

    /// Invoice payload
    public let invoicePayload: Data

    /// True, if this is the first recurring payment
    public let isFirstRecurring: Bool

    /// True, if this is a recurring payment
    public let isRecurring: Bool

    /// Information about the order; may be null
    public let orderInfo: OrderInfo?

    /// Provider payment identifier
    public let providerPaymentChargeId: String

    /// Identifier of the shipping option chosen by the user; may be empty if not applicable
    public let shippingOptionId: String

    /// Telegram payment identifier
    public let telegramPaymentChargeId: String

    /// Total price for the product, in the smallest units of the currency
    public let totalAmount: Int64


    public init(
        currency: String,
        invoicePayload: Data,
        isFirstRecurring: Bool,
        isRecurring: Bool,
        orderInfo: OrderInfo?,
        providerPaymentChargeId: String,
        shippingOptionId: String,
        telegramPaymentChargeId: String,
        totalAmount: Int64
    ) {
        self.currency = currency
        self.invoicePayload = invoicePayload
        self.isFirstRecurring = isFirstRecurring
        self.isRecurring = isRecurring
        self.orderInfo = orderInfo
        self.providerPaymentChargeId = providerPaymentChargeId
        self.shippingOptionId = shippingOptionId
        self.telegramPaymentChargeId = telegramPaymentChargeId
        self.totalAmount = totalAmount
    }
}

/// Telegram Premium was gifted to the user
public struct MessageGiftedPremium: Codable, Equatable, Hashable {

    /// The paid amount, in the smallest units of the currency
    public let amount: Int64

    /// Cryptocurrency used to pay for the gift; may be empty if none
    public let cryptocurrency: String

    /// The paid amount, in the smallest units of the cryptocurrency; 0 if none
    public let cryptocurrencyAmount: TdInt64

    /// Currency for the paid amount
    public let currency: String

    /// The identifier of a user that gifted Telegram Premium; 0 if the gift was anonymous
    public let gifterUserId: Int64

    /// Number of months the Telegram Premium subscription will be active
    public let monthCount: Int

    /// A sticker to be shown in the message; may be null if unknown
    public let sticker: Sticker?


    public init(
        amount: Int64,
        cryptocurrency: String,
        cryptocurrencyAmount: TdInt64,
        currency: String,
        gifterUserId: Int64,
        monthCount: Int,
        sticker: Sticker?
    ) {
        self.amount = amount
        self.cryptocurrency = cryptocurrency
        self.cryptocurrencyAmount = cryptocurrencyAmount
        self.currency = currency
        self.gifterUserId = gifterUserId
        self.monthCount = monthCount
        self.sticker = sticker
    }
}

/// A Telegram Premium gift code was created for the user
public struct MessagePremiumGiftCode: Codable, Equatable, Hashable {

    /// The paid amount, in the smallest units of the currency; 0 if unknown
    public let amount: Int64

    /// The gift code
    public let code: String

    /// Identifier of a chat or a user that created the gift code; may be null if unknown
    public let creatorId: MessageSender?

    /// Cryptocurrency used to pay for the gift; may be empty if none or unknown
    public let cryptocurrency: String

    /// The paid amount, in the smallest units of the cryptocurrency; 0 if unknown
    public let cryptocurrencyAmount: TdInt64

    /// Currency for the paid amount; empty if unknown
    public let currency: String

    /// True, if the gift code was created for a giveaway
    public let isFromGiveaway: Bool

    /// True, if the winner for the corresponding Telegram Premium subscription wasn't chosen
    public let isUnclaimed: Bool

    /// Number of months the Telegram Premium subscription will be active after code activation
    public let monthCount: Int

    /// A sticker to be shown in the message; may be null if unknown
    public let sticker: Sticker?


    public init(
        amount: Int64,
        code: String,
        creatorId: MessageSender?,
        cryptocurrency: String,
        cryptocurrencyAmount: TdInt64,
        currency: String,
        isFromGiveaway: Bool,
        isUnclaimed: Bool,
        monthCount: Int,
        sticker: Sticker?
    ) {
        self.amount = amount
        self.code = code
        self.creatorId = creatorId
        self.cryptocurrency = cryptocurrency
        self.cryptocurrencyAmount = cryptocurrencyAmount
        self.currency = currency
        self.isFromGiveaway = isFromGiveaway
        self.isUnclaimed = isUnclaimed
        self.monthCount = monthCount
        self.sticker = sticker
    }
}

/// A Telegram Premium giveaway
public struct MessagePremiumGiveaway: Codable, Equatable, Hashable {

    /// Number of months the Telegram Premium subscription will be active after code activation
    public let monthCount: Int

    /// Giveaway parameters
    public let parameters: PremiumGiveawayParameters

    /// A sticker to be shown in the message; may be null if unknown
    public let sticker: Sticker?

    /// Number of users which will receive Telegram Premium subscription gift codes
    public let winnerCount: Int


    public init(
        monthCount: Int,
        parameters: PremiumGiveawayParameters,
        sticker: Sticker?,
        winnerCount: Int
    ) {
        self.monthCount = monthCount
        self.parameters = parameters
        self.sticker = sticker
        self.winnerCount = winnerCount
    }
}

/// A Telegram Premium giveaway without public winners has been completed for the chat
public struct MessagePremiumGiveawayCompleted: Codable, Equatable, Hashable {

    /// Identifier of the message with the giveaway; can be 0 if the message was deleted
    public let giveawayMessageId: Int64

    /// Number of undistributed prizes
    public let unclaimedPrizeCount: Int

    /// Number of winners in the giveaway
    public let winnerCount: Int


    public init(
        giveawayMessageId: Int64,
        unclaimedPrizeCount: Int,
        winnerCount: Int
    ) {
        self.giveawayMessageId = giveawayMessageId
        self.unclaimedPrizeCount = unclaimedPrizeCount
        self.winnerCount = winnerCount
    }
}

/// A Telegram Premium giveaway with public winners has been completed for the chat
public struct MessagePremiumGiveawayWinners: Codable, Equatable, Hashable {

    /// Point in time (Unix timestamp) when the winners were selected. May be bigger than winners selection date specified in parameters of the giveaway
    public let actualWinnersSelectionDate: Int

    /// Number of other chats that participated in the giveaway
    public let additionalChatCount: Int

    /// Identifier of the channel chat, which was automatically boosted by the winners of the giveaway for duration of the Premium subscription
    public let boostedChatId: Int64

    /// Identifier of the message with the giveaway in the boosted chat
    public let giveawayMessageId: Int64

    /// Number of months the Telegram Premium subscription will be active after code activation
    public let monthCount: Int

    /// True, if only new members of the chats were eligible for the giveaway
    public let onlyNewMembers: Bool

    /// Additional description of the giveaway prize
    public let prizeDescription: String

    /// Number of undistributed prizes
    public let unclaimedPrizeCount: Int

    /// True, if the giveaway was canceled and was fully refunded
    public let wasRefunded: Bool

    /// Total number of winners in the giveaway
    public let winnerCount: Int

    /// Up to 100 user identifiers of the winners of the giveaway
    public let winnerUserIds: [Int64]


    public init(
        actualWinnersSelectionDate: Int,
        additionalChatCount: Int,
        boostedChatId: Int64,
        giveawayMessageId: Int64,
        monthCount: Int,
        onlyNewMembers: Bool,
        prizeDescription: String,
        unclaimedPrizeCount: Int,
        wasRefunded: Bool,
        winnerCount: Int,
        winnerUserIds: [Int64]
    ) {
        self.actualWinnersSelectionDate = actualWinnersSelectionDate
        self.additionalChatCount = additionalChatCount
        self.boostedChatId = boostedChatId
        self.giveawayMessageId = giveawayMessageId
        self.monthCount = monthCount
        self.onlyNewMembers = onlyNewMembers
        self.prizeDescription = prizeDescription
        self.unclaimedPrizeCount = unclaimedPrizeCount
        self.wasRefunded = wasRefunded
        self.winnerCount = winnerCount
        self.winnerUserIds = winnerUserIds
    }
}

/// The current user shared users, which were requested by the bot
public struct MessageUsersShared: Codable, Equatable, Hashable {

    /// Identifier of the keyboard button with the request
    public let buttonId: Int

    /// Identifier of the shared users
    public let userIds: [Int64]


    public init(
        buttonId: Int,
        userIds: [Int64]
    ) {
        self.buttonId = buttonId
        self.userIds = userIds
    }
}

/// The current user shared a chat, which was requested by the bot
public struct MessageChatShared: Codable, Equatable, Hashable {

    /// Identifier of the keyboard button with the request
    public let buttonId: Int

    /// Identifier of the shared chat
    public let chatId: Int64


    public init(
        buttonId: Int,
        chatId: Int64
    ) {
        self.buttonId = buttonId
        self.chatId = chatId
    }
}

/// The user allowed the bot to send messages
public struct MessageBotWriteAccessAllowed: Codable, Equatable, Hashable {

    /// The reason why the bot was allowed to write messages
    public let reason: BotWriteAccessAllowReason


    public init(reason: BotWriteAccessAllowReason) {
        self.reason = reason
    }
}

/// Data from a Web App has been sent to a bot
public struct MessageWebAppDataSent: Codable, Equatable, Hashable {

    /// Text of the keyboardButtonTypeWebApp button, which opened the Web App
    public let buttonText: String


    public init(buttonText: String) {
        self.buttonText = buttonText
    }
}

/// Data from a Web App has been received; for bots only
public struct MessageWebAppDataReceived: Codable, Equatable, Hashable {

    /// Text of the keyboardButtonTypeWebApp button, which opened the Web App
    public let buttonText: String

    /// The data
    public let data: String


    public init(
        buttonText: String,
        data: String
    ) {
        self.buttonText = buttonText
        self.data = data
    }
}

/// Telegram Passport data has been sent to a bot
public struct MessagePassportDataSent: Codable, Equatable, Hashable {

    /// List of Telegram Passport element types sent
    public let types: [PassportElementType]


    public init(types: [PassportElementType]) {
        self.types = types
    }
}

/// Telegram Passport data has been received; for bots only
public struct MessagePassportDataReceived: Codable, Equatable, Hashable {

    /// Encrypted data credentials
    public let credentials: EncryptedCredentials

    /// List of received Telegram Passport elements
    public let elements: [EncryptedPassportElement]


    public init(
        credentials: EncryptedCredentials,
        elements: [EncryptedPassportElement]
    ) {
        self.credentials = credentials
        self.elements = elements
    }
}

/// A user in the chat came within proximity alert range
public struct MessageProximityAlertTriggered: Codable, Equatable, Hashable {

    /// The distance between the users
    public let distance: Int

    /// The identifier of a user or chat that triggered the proximity alert
    public let travelerId: MessageSender

    /// The identifier of a user or chat that subscribed for the proximity alert
    public let watcherId: MessageSender


    public init(
        distance: Int,
        travelerId: MessageSender,
        watcherId: MessageSender
    ) {
        self.distance = distance
        self.travelerId = travelerId
        self.watcherId = watcherId
    }
}

